package cn.csm.jwtlogin.jwt;

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Date;
import java.util.UUID;

/**
 * @ClassName JwtTokenProvider
 * @Description jwt token工具类
 * @Author shiming.chen
 * @Date 2020/2/17 9:09
 */
@Component
public class JwtProvider implements InitializingBean {

    Logger log = LoggerFactory.getLogger(this.getClass());

    /** Request Headers ： Authorization */
    public static final String HEADER = "Authorization";

    /** 令牌前缀，最后留个空格 Bearer */
    public static final String TOKEN_START_WITH = "Bearer ";

    //如果要使用HMAC-SHA算法对JWS进行签名，并且具有密钥String或 编码的字节数组，则需要将其转换为SecretKey实例以用作signWith方法参数
    public static final String BASE_64_SECRET = "X3U9IsrWaSKouYLUZycx2U9ckmk1Sr6DQpbK47+ASAg=";

    public static void main(String[] args) {
        SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String BASE_64_SECRET = Encoders.BASE64.encode(key.getEncoded());
    }

    private Key key;

    @Override
    public void afterPropertiesSet() {
        byte[] keyBytes = Decoders.BASE64.decode(BASE_64_SECRET);
        this.key = Keys.hmacShaKeyFor(keyBytes);
    }

    /**
     *  创建token
     * @param subject 主题，一般可以放用户名
     * @param expiration 过期时间间隔，秒
     * @param tokenType @{TokenType} token类型
     * @return token
     */
    public String createToken(String subject, int expiration,TokenType tokenType) {
        return Jwts.builder()
                .setIssuer("issuer")    //发行方
                .setSubject(subject)  //主题
                .setAudience("audience") //受众群体
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) //到期时间
                .setNotBefore(new Date()) //不早于
                .setIssuedAt(new Date()) // 签发时间
                .setId(UUID.randomUUID().toString()) //JWT ID
                .claim("type",tokenType)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    public Claims getClaims(String token){
        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
    }

    public String getSubject(String token) {
        return getClaims(token).getSubject();
    }

    public boolean validateToken(String jws) {
        try {
//            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jws);
            Jwts.parserBuilder().require("type", TokenType.ACCESS.name()).setSigningKey(key).build().parseClaimsJws(jws);
            return true;
        } catch (JwtException e) {
            log.info("Invalid JWT signature");
        }
        return false;
    }

    public boolean validateRefresh(String jws){
        try {
            Jwts.parserBuilder().require("type", TokenType.REFRESH.name()).setSigningKey(key).build().parseClaimsJws(jws);
            return true;
        } catch(InvalidClaimException ice) {
            log.info("invalid JWT signature");
        }
        return false;
    }

    public String getToken(HttpServletRequest request){
        final String bearerToken = request.getHeader(HEADER);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_START_WITH)) {
            return bearerToken.substring(7);
        }
        return null;
    }

}
